using System;
using System.Diagnostics;

namespace Behaviours.Log
{
    public enum LogLevel:byte
    {
        Default,
        Trace,
        Debug,
        Info,
        Warning,
    }
    public static class Logger
    {
        private static LogLevel _logLevel = LogLevel.Debug;
        
        public static ILogger ILog { get; }

        static Logger()
        {
#if SERVER
            ILog = new NLogger("Server");
#else
            ILog = new UnityLogger();
#endif
        }

        public static void SetLogLevel(LogLevel level)
        {
            _logLevel = level;
        }
        public static bool IsEnabled(LogLevel level)
        {
            return _logLevel <= level;
        }
        
        public static Action<string, object[]> DebugCallback;
        public static Action<string> ErrorCallback;

        public static void Trace(string msg)
        {
            if (!IsEnabled(LogLevel.Debug))
            {
                return;
            }
            DebugCallback?.Invoke(msg, null);
            StackTrace st = new StackTrace(1, true);
            ILog.Trace($"{msg}\n{st}");
        }

        public static void Debug(string msg)
        {
            if (!IsEnabled(LogLevel.Debug))
            {
                return;
            }
            DebugCallback?.Invoke(msg, null);
            ILog.Debug(msg);
        }

        public static void Info(string msg)
        {
            if (!IsEnabled(LogLevel.Info))
            {
                return;
            }
            ILog.Info(msg);
        }

        public static void TraceInfo(string msg)
        {
            if (!IsEnabled(LogLevel.Info))
            {
                return;
            }
            StackTrace st = new StackTrace(1, true);
            ILog.Trace($"{msg}\n{st}");
        }

        public static void Warning(string msg)
        {
            if (!IsEnabled(LogLevel.Warning))
            {
                return;
            }

            ILog.Warning(msg);
        }

        public static void Error(string msg)
        {
            StackTrace st = new StackTrace(1, true);
            ErrorCallback?.Invoke($"{msg}\n{st}");
            ILog.Error($"{msg}\n{st}");
        }

        public static void Error(System.Exception e)
        {
            string str = e.ToString();
            ErrorCallback?.Invoke(str);
            ILog.Error(str);
        }

        public static void Trace(string message, params object[] args)
        {
            if (!IsEnabled(LogLevel.Trace))
            {
                return;
            }
            DebugCallback?.Invoke(message, args);
            StackTrace st = new StackTrace(1, true);
            ILog.Trace($"{string.Format(message, args)}\n{st}");
        }

        public static void Warning(string message, params object[] args)
        {
            if (!IsEnabled(LogLevel.Warning))
            {
                return;
            }
            ILog.Warning(string.Format(message, args));
        }

        public static void Info(string message, params object[] args)
        {
            if (!IsEnabled(LogLevel.Info))
            {
                return;
            }
            ILog.Info(string.Format(message, args));
        }

        public static void Debug(string message, params object[] args)
        {
            if (!IsEnabled(LogLevel.Debug))
            {
                return;
            }
            DebugCallback?.Invoke(message, args);
            ILog.Debug(string.Format(message, args));

        }

        public static void Error(string message, params object[] args)
        {
            StackTrace st = new StackTrace(1, true);
            string s = string.Format(message, args) + '\n' + st;
            ErrorCallback?.Invoke(s);
            ILog.Error(s);
        }
    }
}